#define MAX_CLIENT_COUNT 1024

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <sqlite3.h>

sqlite3 *db;
char *dbErrMsg = NULL;

// 从数组中删除特定的元素，返回新数组的长度
int removeItemFromArray(int arr[], int length, int removeItem) {
    int new_length = 0;
    for (int i = 0; i < length; i++) {
        if (arr[i] != removeItem) {
            arr[new_length++] = arr[i];
        }
    }
    return new_length;
}

int query_count_callback(void *NoUsed, int argc, char **argv, char **azColName) {
    // 有且只有一行一列数据
    printf("查询到客户端的数量是%s\n", argv[0]);
    fflush(stdout);
    return atoi(argv[0]);
}

int query_socket_callback(void *buff, int argc, char **argv, char **azColName) {
    for (int i = 0; i < argc; i++) {
        int fd = atoi(argv[0]);
        // 广播

        send(fd, buff, strlen(buff), 0);
        // 没有使用线程锁，导致打印的i的值为缓存的值
        // printf("广播给第%d个socket，发送的数据是%s\n", i + 1, buff);
        printf("广播给第socket_id:%d，发送的数据是%s\n", fd, buff);
    }
    fflush(stdout);
    return 0;
}

// 处理客户端的连接  在子线程中执行
int handle_client(void *arg) {
    int client_socket = *((int *) arg);
    free(arg);
    // 如果客户端数量超限，则直接返回
    // to do
    // 查询目前客户端数量
    char *query_count_sql = "select count(id) from socket";
    int current_client_count = sqlite3_exec(db, query_count_sql, query_count_callback, NULL, &dbErrMsg);
    if (current_client_count > MAX_CLIENT_COUNT) {
        printf("聊天人数过多，请稍后再试\n");
        return -1;
    }
    // 如果使用字符串拼接sql，会产生sql的问题，改用sql预编译的方式进行执行 在sql中使用？表示占位
    sqlite3_stmt *stmt;  // sql语句
    char *add_client_socket_sql = "insert into socket(socket_id) values(?)";
    // sqlite3_prepare_v2将char *转换成预编译sql语句对象
    int rc = sqlite3_prepare_v2(db, add_client_socket_sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        printf("转换失败 %s\n", sqlite3_errmsg(db));
    } else {
        printf("转换成功\n");
    }
    fflush(stdout);
    // 绑定？数据
    rc = sqlite3_bind_int(stmt, 1, client_socket);
    if (rc != SQLITE_OK) {
        printf("绑定失败 %s\n", sqlite3_errmsg(db));
    } else {
        printf("绑定成功\n");
    }
    fflush(stdout);
    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        printf("执行失败 插入数据失败 socket_id是：%d  %s\n", client_socket, sqlite3_errmsg(db));
    } else {
        printf("执行成功 插入数据成功 插入的socket_id是：%d\n", client_socket);
    }
    fflush(stdout);
    // 释放缓存
    sqlite3_finalize(stmt);

    // 处理客户端发过来的字符
    char buffer[1024];
    printf("新客户端来连接  线程的ID = %ld\n", pthread_self());
    printf("新客户端来连接  客户端的ID = %d\n", client_socket);
    fflush(stdout);

    for (;;) {
        // 清空缓冲区
        memset(buffer, 0, sizeof(buffer));
        ssize_t bytes_read = read(client_socket, buffer, sizeof(buffer) - 1);
        if (bytes_read <= 0) {
            printf("客户端断开  线程的ID = %ld\n", pthread_self());
            printf("客户端断开  ID:%d\n", client_socket);
            fflush(stdout);
            // 从client_sockets数组中删除当前socket
            // sqlite3_stmt *stmt;
            char *delete_client_socket_sql = "delete from socket where socket_id = ?";
            rc = sqlite3_prepare_v2(db, delete_client_socket_sql, -1, &stmt, NULL);
            if (rc != SQLITE_OK) {
                printf("转换失败 %s\n", dbErrMsg);
            } else {
                printf("转换成功\n");
            }
            fflush(stdout);
            // 绑定？数据
            rc = sqlite3_bind_int(stmt, 1, client_socket);
            if (rc != SQLITE_OK) {
                printf("绑定失败 %s\n", sqlite3_errmsg(db));
            } else {
                printf("绑定成功\n");
            }
            fflush(stdout);
            rc = sqlite3_step(stmt);
            if (rc != SQLITE_DONE) {
                printf("执行失败，删除数据失败，socket_id是:%d  %s\n", client_socket, sqlite3_errmsg(db));
            } else {
                printf("执行成功，删除数据成功，删除的socket_id是:%d  %s\n", client_socket, sqlite3_errmsg(db));
            }
            fflush(stdout);
            sqlite3_finalize(stmt);

            rc = sqlite3_exec(db, delete_client_socket_sql, NULL, NULL, &dbErrMsg);
            if (rc != SQLITE_OK) {
                printf("删除失败%s\n", dbErrMsg);
                return -1;
            }
            break;
        }
        printf("线程的ID = %ld 接收到的消息：%s\n", pthread_self(), buffer);
        fflush(stdout);
        // 广播消息给所有的客户端  附加：没有使用锁的机制处理并发问题
        char *query_socket_sql = "select socket_id from socket";
        rc = sqlite3_exec(db, query_socket_sql, query_socket_callback, buffer, &dbErrMsg);
        if (rc != SQLITE_OK) {
            printf("查询失败%s\n", dbErrMsg);
            return -1;
        }
    }
}

int main() {
    // socket编程， 建立的服务端
    const int hostshort = 9527;
    // 建立socket
    // 返回文件描述符，-1表示失败
    // 参数1: AF_INET使用ipv4  AF_INET6 使用ipv6
    // 参数2: SOCK_STREAM表示tcp   SOCK_DGRAM表示udp
    // 参数3: 参考注释
    int server_fd = socket(AF_INET,SOCK_STREAM, 0);
    if (server_fd <= 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    // 复用socket
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));

    // 地址信息
    struct sockaddr_in address;
    int addrelen = sizeof(address);
    // 使用ip协议
    address.sin_family = AF_INET;
    // 绑定任意地址  表示通过本机的所有IP都可以连接
    address.sin_addr.s_addr = INADDR_ANY;

    // htons 表示底层数据编码方式由小端改成大端
    address.sin_port = htons(hostshort);
    int bindResult = bind(server_fd, (struct sockaddr *) &address, sizeof(address));
    if (bindResult < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    // 进行监听  同时处理5个请求  否则排队
    int listenResult = listen(server_fd, 5);
    if (listenResult < 0) {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }
    printf("Server listening on port 9527\n");
    fflush(stdout);

    // 打开数据库
    int rc = sqlite3_open("/chat_system/chat_system.db", &db);
    if (rc != SQLITE_OK) {
        printf("Can't open database: %s\n", sqlite3_errmsg(db));
        return EXIT_FAILURE;
    }

    // 清空socket表数据 否则会存在脏数据
    char *clear_socket = "delete from socket";
    rc = sqlite3_exec(db, clear_socket, NULL, NULL, &dbErrMsg);
    if (rc != SQLITE_OK) {
        printf("删除失败 %s\n", dbErrMsg);
    } else {
        printf("清除socket成功\n");
    }
    fflush(stdout);

    for (;;) {
        // 使用多线程处理每个不同的socket
        int *client_socket = (int *) malloc(sizeof(int));
        // 返回客户端的socket
        *client_socket = accept(server_fd, (struct sockaddr *) &address, (socklen_t *) &addrelen);
        if (client_socket < 0) {
            perror("accept failed");
            continue;
        }
        printf("Client connected\n");
        fflush(stdout);
        // 创建多线程，处理不同的socket
        pthread_t t_id;
        pthread_create(&t_id, NULL, handle_client, client_socket);
    }

    sqlite3_close(db);
    close(server_fd);
    return 0;
}